/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#ifndef MDSS_PANEL_H
#define MDSS_PANEL_H

#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/stringify.h>
#include <linux/types.h>
#include <linux/debugfs.h>

#define KHZ_TO_HZ 1000

/* panel id type */
struct panel_id {
	u16 id;
	u16 type;
};

enum fps_resolution {
	FPS_RESOLUTION_DEFAULT,
	FPS_RESOLUTION_HZ,
	FPS_RESOLUTION_KHZ,
};

#define DEFAULT_FRAME_RATE	60
#define DEFAULT_ROTATOR_FRAME_RATE 120
#define ROTATOR_LOW_FRAME_RATE 30
#define MDSS_DSI_RST_SEQ_LEN	10
/* worst case prefill lines for all chipsets including all vertical blank */
#define MDSS_MDP_MAX_PREFILL_FETCH 25

#define OVERRIDE_CFG	"override"
#define SIM_PANEL	"sim"
#define SIM_SW_TE_PANEL	"sim-swte"
#define SIM_HW_TE_PANEL	"sim-hwte"

/* panel type list */
#define NO_PANEL		0xffff	/* No Panel */
#define MDDI_PANEL		1	/* MDDI */
#define EBI2_PANEL		2	/* EBI2 */
#define LCDC_PANEL		3	/* internal LCDC type */
#define EXT_MDDI_PANEL		4	/* Ext.MDDI */
#define TV_PANEL		5	/* TV */
#define HDMI_PANEL		6	/* HDMI TV */
#define DTV_PANEL		7	/* DTV */
#define MIPI_VIDEO_PANEL	8	/* MIPI */
#define MIPI_CMD_PANEL		9	/* MIPI */
#define WRITEBACK_PANEL		10	/* Wifi display */
#define LVDS_PANEL		11	/* LVDS */
#define EDP_PANEL		12	/* LVDS */

#define DSC_PPS_LEN		128

/* HDR propeties count */
#define DISPLAY_PRIMARIES_COUNT	8	/* WRGB x and y values*/

static inline const char *mdss_panel2str(u32 panel)
{
	static const char const *names[] = {
#define PANEL_NAME(n) [n ## _PANEL] = __stringify(n)
		PANEL_NAME(MIPI_VIDEO),
		PANEL_NAME(MIPI_CMD),
		PANEL_NAME(EDP),
		PANEL_NAME(HDMI),
		PANEL_NAME(DTV),
		PANEL_NAME(WRITEBACK),
#undef PANEL_NAME
	};

	if (panel >= ARRAY_SIZE(names) || !names[panel])
		return "UNKNOWN";

	return names[panel];
}

/* panel class */
enum {
	DISPLAY_LCD = 0,	/* lcd = ebi2/mddi */
	DISPLAY_LCDC,		/* lcdc */
	DISPLAY_TV,		/* TV Out */
	DISPLAY_EXT_MDDI,	/* External MDDI */
	DISPLAY_WRITEBACK,
};

/* panel device locaiton */
enum {
	DISPLAY_1 = 0,		/* attached as first device */
	DISPLAY_2,		/* attached on second device */
	DISPLAY_3,		/* attached on third device */
	DISPLAY_4,		/* attached on fourth device */
	MAX_PHYS_TARGET_NUM,
};

enum {
	MDSS_PANEL_INTF_INVALID = -1,
	MDSS_PANEL_INTF_DSI,
	MDSS_PANEL_INTF_EDP,
	MDSS_PANEL_INTF_HDMI,
};

enum {
	MDSS_PANEL_POWER_OFF = 0,
	MDSS_PANEL_POWER_ON,
	MDSS_PANEL_POWER_LP1,
	MDSS_PANEL_POWER_LP2,
};

enum {
	MDSS_PANEL_LOW_PERSIST_MODE_OFF = 0,
	MDSS_PANEL_LOW_PERSIST_MODE_ON,
};

enum {
	MODE_GPIO_NOT_VALID = 0,
	MODE_GPIO_HIGH,
	MODE_GPIO_LOW,
};

/*
 * enum sim_panel_modes - Different panel modes for simulator panels
 *
 * @SIM_MODE:		Disables all host reads for video mode simulator panels.
 * @SIM_SW_TE_MODE:	Disables all host reads and genereates the SW TE. Used
 *                      for cmd mode simulator panels.
 * @SIM_HW_TE_MODE:	Disables all host reads and expects TE from hardware
 *                      (terminator card). Used for cmd mode simulator panels.
 */
enum {
	SIM_MODE = 1,
	SIM_SW_TE_MODE,
	SIM_HW_TE_MODE,
};

struct mdss_rect {
	u16 x;
	u16 y;
	u16 w;
	u16 h;
};

#define MDSS_MAX_PANEL_LEN      256
#define MDSS_INTF_MAX_NAME_LEN 5
#define MDSS_DISPLAY_ID_MAX_LEN 16
struct mdss_panel_intf {
	char name[MDSS_INTF_MAX_NAME_LEN];
	int  type;
};

struct mdss_panel_cfg {
	char arg_cfg[MDSS_MAX_PANEL_LEN + 1];
	int  pan_intf;
	bool lk_cfg;
	bool init_done;
};

#define MDP_INTF_DSI_CMD_FIFO_UNDERFLOW		0x0001
#define MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW	0x0002


enum {
	MDP_INTF_CALLBACK_DSI_WAIT,
};

struct mdss_intf_recovery {
	int (*fxn)(void *ctx, int event);
	void *data;
};

/**
 * enum mdss_intf_events - Different events generated by MDP core
 *
 * @MDSS_EVENT_RESET:		MDP control path is being (re)initialized.
 * @MDSS_EVENT_LINK_READY	Interface data path inited to ready state.
 * @MDSS_EVENT_UNBLANK:		Sent before first frame update from MDP is
 *				sent to panel.
 * @MDSS_EVENT_PANEL_ON:	After first frame update from MDP.
 * @MDSS_EVENT_POST_PANEL_ON	send 2nd phase panel on commands to panel
 * @MDSS_EVENT_BLANK:		MDP has no contents to display only blank screen
 *				is shown in panel. Sent before panel off.
 * @MDSS_EVENT_PANEL_OFF:	MDP has suspended frame updates, panel should be
 *				completely shutdown after this call.
 * @MDSS_EVENT_CLOSE:		MDP has tore down entire session.
 * @MDSS_EVENT_SUSPEND:		Propagation of power suspend event.
 * @MDSS_EVENT_RESUME:		Propagation of power resume event.
 * @MDSS_EVENT_CHECK_PARAMS:	Event generated when a panel reconfiguration is
 *				requested including when resolution changes.
 *				The event handler receives pointer to
 *				struct mdss_panel_info and should return one of:
 *				 - negative if the configuration is invalid
 *				 - 0 if there is no panel reconfig needed
 *				 - 1 if reconfig is needed to take effect
 * @MDSS_EVENT_CONT_SPLASH_BEGIN: Special event used to handle transition of
 *				display state from boot loader to panel driver.
 *				The event handler will disable the panel.
 * @MDSS_EVENT_CONT_SPLASH_FINISH: Special event used to handle transition of
 *				display state from boot loader to panel driver.
 *				The event handler will enable the panel and
 *				vote for the display clocks.
 * @MDSS_EVENT_PANEL_UPDATE_FPS: Event to update the frame rate of the panel.
 * @MDSS_EVENT_FB_REGISTERED:	Called after fb dev driver has been registered,
 *				panel driver gets ptr to struct fb_info which
 *				holds fb dev information.
 * @MDSS_EVENT_PANEL_CLK_CTRL:	panel clock control
 *				- 0 clock disable
 *				- 1 clock enable
 * @MDSS_EVENT_DSI_CMDLIST_KOFF: acquire dsi_mdp_busy lock before kickoff.
 * @MDSS_EVENT_ENABLE_PARTIAL_ROI: Event to update ROI of the panel.
 * @MDSS_EVENT_DSC_PPS_SEND: Event to send DSC PPS command to panel.
 * @MDSS_EVENT_DSI_STREAM_SIZE: Event to update DSI controller's stream size
 * @MDSS_EVENT_DSI_UPDATE_PANEL_DATA: Event to update the dsi driver structures
 *				based on the dsi mode passed as argument.
 *				- 0: update to video mode
 *				- 1: update to command mode
 * @MDSS_EVENT_REGISTER_RECOVERY_HANDLER: Event to recover the interface in
 *					case there was any errors detected.
 * @MDSS_EVENT_REGISTER_MDP_CALLBACK: Event to register callback to MDP driver.
 * @MDSS_EVENT_DSI_PANEL_STATUS: Event to check the panel status
 *				<= 0: panel check fail
 *				>  0: panel check success
 * @MDSS_EVENT_DSI_DYNAMIC_SWITCH: Send DCS command to panel to initiate
 *				switching panel to new mode
 *				- MIPI_VIDEO_PANEL: switch to video mode
 *				- MIPI_CMD_PANEL: switch to command mode
 * @MDSS_EVENT_DSI_RECONFIG_CMD: Setup DSI controller in new mode
 *				- MIPI_VIDEO_PANEL: switch to video mode
 *				- MIPI_CMD_PANEL: switch to command mode
 * @MDSS_EVENT_DSI_RESET_WRITE_PTR: Reset the write pointer coordinates on
 *				the panel.
 * @MDSS_EVENT_PANEL_TIMING_SWITCH: Panel timing switch is requested.
 *				Argument provided is new panel timing.
 */
enum mdss_intf_events {
	MDSS_EVENT_RESET = 1,
	MDSS_EVENT_LINK_READY,
	MDSS_EVENT_UNBLANK,
	MDSS_EVENT_PANEL_ON,
	MDSS_EVENT_POST_PANEL_ON,
	MDSS_EVENT_BLANK,
	MDSS_EVENT_PANEL_OFF,
	MDSS_EVENT_CLOSE,
	MDSS_EVENT_SUSPEND,
	MDSS_EVENT_RESUME,
	MDSS_EVENT_CHECK_PARAMS,
	MDSS_EVENT_CONT_SPLASH_BEGIN,
	MDSS_EVENT_CONT_SPLASH_FINISH,
	MDSS_EVENT_PANEL_UPDATE_FPS,
	MDSS_EVENT_FB_REGISTERED,
	MDSS_EVENT_PANEL_CLK_CTRL,
	MDSS_EVENT_DSI_CMDLIST_KOFF,
	MDSS_EVENT_ENABLE_PARTIAL_ROI,
	MDSS_EVENT_DSC_PPS_SEND,
	MDSS_EVENT_DSI_STREAM_SIZE,
	MDSS_EVENT_DSI_UPDATE_PANEL_DATA,
	MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
	MDSS_EVENT_REGISTER_MDP_CALLBACK,
	MDSS_EVENT_DSI_PANEL_STATUS,
	MDSS_EVENT_DSI_DYNAMIC_SWITCH,
	MDSS_EVENT_DSI_RECONFIG_CMD,
	MDSS_EVENT_DSI_RESET_WRITE_PTR,
	MDSS_EVENT_PANEL_TIMING_SWITCH,
	MDSS_EVENT_UPDATE_PARAMS,
	MDSS_EVENT_MAX,
};

struct lcd_panel_info {
	u32 h_back_porch;
	u32 h_front_porch;
	u32 h_pulse_width;
	u32 v_back_porch;
	u32 v_front_porch;
	u32 v_pulse_width;
	u32 border_clr;
	u32 underflow_clr;
	u32 hsync_skew;
	u32 border_top;
	u32 border_bottom;
	u32 border_left;
	u32 border_right;
	/* Pad width */
	u32 xres_pad;
	/* Pad height */
	u32 yres_pad;
	u32 frame_rate;
};


/* DSI PHY configuration */
struct mdss_dsi_phy_ctrl {
	char regulator[7];	/* 8996, 1 * 5 */
	char timing[12];
	char ctrl[4];
	char strength[10];	/* 8996, 2 * 5 */
	char bistctrl[6];
	uint32_t pll[21];
	char lanecfg[45];	/* 8996, 4 * 5 */
	bool reg_ldo_mode;

	char timing_8996[40];/* 8996, 8 * 5 */
	char regulator_len;
	char strength_len;
	char lanecfg_len;
};

/**
 * enum dynamic_mode_switch - Dynamic mode switch methods
 * @DYNAMIC_MODE_SWITCH_DISABLED: Dynamic mode switch is not supported
 * @DYNAMIC_MODE_SWITCH_SUSPEND_RESUME: Switch requires panel suspend/resume
 * @DYNAMIC_MODE_SWITCH_IMMEDIATE: Supports video/cmd mode switch immediately
 * @DYNAMIC_MODE_RESOLUTION_SWITCH_IMMEDIATE: Panel supports display resolution
 * switch immediately.
 **/
enum dynamic_mode_switch {
	DYNAMIC_MODE_SWITCH_DISABLED = 0,
	DYNAMIC_MODE_SWITCH_SUSPEND_RESUME,
	DYNAMIC_MODE_SWITCH_IMMEDIATE,
	DYNAMIC_MODE_RESOLUTION_SWITCH_IMMEDIATE,
};

/**
 * enum dynamic_switch_modes - Type of dynamic mode switch to be given as
 * argument to MDSS_EVENT_DSI_DYNAMIC_SWITCH event
 * @SWITCH_TO_CMD_MODE: Switch from DSI video mode to command mode
 * @SWITCH_TO_VIDEO_MODE: Switch from DSI command mode to video mode
 * @SWITCH_RESOLUTION: Switch only display resolution
 **/
enum dynamic_switch_modes {
	SWITCH_MODE_UNKNOWN = 0,
	SWITCH_TO_CMD_MODE,
	SWITCH_TO_VIDEO_MODE,
	SWITCH_RESOLUTION,
};

/**
 * struct mdss_panel_timing - structure for panel timing information
 * @list: List head ptr to track within panel data timings list
 * @name: A unique name of this timing that can be used to identify it
 * @xres: Panel width
 * @yres: Panel height
 * @h_back_porch: Horizontal back porch
 * @h_front_porch: Horizontal front porch
 * @h_pulse_width: Horizontal pulse width
 * @hsync_skew: Horizontal sync skew
 * @v_back_porch: Vertical back porch
 * @v_front_porch: Vertical front porch
 * @v_pulse_width: Vertical pulse width
 * @border_top: Border color on top
 * @border_bottom: Border color on bottom
 * @border_left: Border color on left
 * @border_right: Border color on right
 * @clk_rate: Pixel clock rate of this panel timing
 * @frame_rate: Display refresh rate
 * @fbc: Framebuffer compression parameters for this display timing
 * @te: Tearcheck parameters for this display timing
 **/
struct mipi_panel_info {
	char boot_mode;	/* identify if mode switched from starting mode */
	char mode;		/* video/cmd */
	char interleave_mode;
	char crc_check;
	char ecc_check;
	char dst_format;	/* shared by video and command */
	char data_lane0;
	char data_lane1;
	char data_lane2;
	char data_lane3;
	char rgb_swap;
	char b_sel;
	char g_sel;
	char r_sel;
	char rx_eot_ignore;
	char tx_eot_append;
	char t_clk_post; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
	char t_clk_pre;  /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
	char vc;	/* virtual channel */
	struct mdss_dsi_phy_ctrl dsi_phy_db;
	/* video mode */
	char pulse_mode_hsa_he;
	char hfp_power_stop;
	char hbp_power_stop;
	char hsa_power_stop;
	char eof_bllp_power_stop;
	char last_line_interleave_en;
	char bllp_power_stop;
	char traffic_mode;
	char frame_rate;
	/* command mode */
	char frame_rate_idle;
	char interleave_max;
	char insert_dcs_cmd;
	char wr_mem_continue;
	char wr_mem_start;
	char te_sel;
	char stream;	/* 0 or 1 */
	char mdp_trigger;
	char dma_trigger;
	/* Dynamic Switch Support */
	enum dynamic_mode_switch dms_mode;

	u32 pixel_packing;
	u32 dsi_pclk_rate;
	/* The packet-size should not bet changed */
	char no_max_pkt_size;
	/* Clock required during LP commands */
	bool force_clk_lane_hs;

	char vsync_enable;
	char hw_vsync_mode;

	char lp11_init;
	u32  init_delay;
	u32  post_init_delay;
	u8 default_lanes;
};

struct edp_panel_info {
	char frame_rate;	/* fps */
};

/**
 * struct dynamic_fps_data - defines dynamic fps related data
 * @hfp: horizontal front porch
 * @hbp: horizontal back porch
 * @hpw: horizontal pulse width
 * @clk_rate: panel clock rate in HZ
 * @fps: frames per second
 */
struct dynamic_fps_data {
	u32 hfp;
	u32 hbp;
	u32 hpw;
	u32 clk_rate;
	u32 fps;
};

/**
 * enum dynamic_fps_update - defines fps update modes
 * @DFPS_SUSPEND_RESUME_MODE: suspend/resume mode
 * @DFPS_IMMEDIATE_CLK_UPDATE_MODE: update fps using clock
 * @DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP: update fps using vertical timings
 * @DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP: update fps using horizontal timings
 * @DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP: update fps using both horizontal
 *  timings and clock.
 * @DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK: update fps using both
 *  horizontal timings, clock need to be caculate base on new clock and
 *  porches.
 * @DFPS_MODE_MAX: defines maximum limit of supported modes.
 */
enum dynamic_fps_update {
	DFPS_SUSPEND_RESUME_MODE,
	DFPS_IMMEDIATE_CLK_UPDATE_MODE,
	DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP,
	DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP,
	DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP,
	DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK,
	DFPS_MODE_MAX
};

enum lvds_mode {
	LVDS_SINGLE_CHANNEL_MODE,
	LVDS_DUAL_CHANNEL_MODE,
};

struct lvds_panel_info {
	enum lvds_mode channel_mode;
	/* Channel swap in dual mode */
	char channel_swap;
};

enum {
	COMPRESSION_NONE,
	COMPRESSION_DSC,
	COMPRESSION_FBC
};

struct dsc_desc {
	u8 version; /* top 4 bits major and lower 4 bits minor version */
	u8 scr_rev; /* 8 bit value for dsc scr revision */

	/*
	 * Following parameters can change per frame if partial update is on
	 */
	int pic_height;
	int pic_width;
	int initial_lines;

	/*
	 * Following parameters are used for DSI and not for MDP. They can
	 * change per frame if partial update is enabled.
	 */
	int pkt_per_line;
	int bytes_in_slice;
	int bytes_per_pkt;
	int eol_byte_num;
	int pclk_per_line;	/* width */

	/*
	 * Following parameters only changes when slice dimensions are changed.
	 */
	int full_frame_slices; /* denotes number of slice per intf */
	int slice_height;
	int slice_width;
	int chunk_size;

	int slice_last_group_size;
	int bpp;	/* target bits per pixel */
	int bpc;	/* uncompressed bits per component */
	int line_buf_depth;
	bool config_by_manufacture_cmd;
	bool block_pred_enable;
	int vbr_enable;
	int enable_422;
	int convert_rgb;
	int input_10_bits;
	int slice_per_pkt;

	int initial_dec_delay;
	int initial_xmit_delay;

	int initial_scale_value;
	int scale_decrement_interval;
	int scale_increment_interval;

	int first_line_bpg_offset;
	int nfl_bpg_offset;
	int slice_bpg_offset;

	int initial_offset;
	int final_offset;

	int rc_model_size;	/* rate_buffer_size */

	int det_thresh_flatness;
	int max_qp_flatness;
	int min_qp_flatness;
	int edge_factor;
	int quant_incr_limit0;
	int quant_incr_limit1;
	int tgt_offset_hi;
	int tgt_offset_lo;
	u32 *buf_thresh;
	char *range_min_qp;
	char *range_max_qp;
	char *range_bpg_offset;
};

struct fbc_panel_info {
	u32 enabled;
	u32 target_bpp;
	u32 comp_mode;
	u32 qerr_enable;
	u32 cd_bias;
	u32 pat_enable;
	u32 vlc_enable;
	u32 bflc_enable;

	u32 line_x_budget;
	u32 block_x_budget;
	u32 block_budget;

	u32 lossless_mode_thd;
	u32 lossy_mode_thd;
	u32 lossy_rgb_thd;
	u32 lossy_mode_idx;

	u32 slice_height;
	bool pred_mode;
	bool enc_mode;
	u32 max_pred_err;
};

struct mdss_mdp_pp_tear_check {
	u32 tear_check_en;
	u32 sync_cfg_height;
	u32 vsync_init_val;
	u32 sync_threshold_start;
	u32 sync_threshold_continue;
	u32 start_pos;
	u32 rd_ptr_irq;
	u32 wr_ptr_irq;
	u32 refx100;
};

struct mdss_panel_roi_alignment {
	u32 xstart_pix_align;
	u32 width_pix_align;
	u32 ystart_pix_align;
	u32 height_pix_align;
	u32 min_width;
	u32 min_height;
};

struct mdss_panel_hdr_properties {
	bool hdr_enabled;

	/* WRGB X and y values arrayed in format */
	/* [WX, WY, RX, RY, GX, GY, BX, BY] */
	u32 display_primaries[DISPLAY_PRIMARIES_COUNT];

	/* peak brightness supported by panel */
	u32 peak_brightness;
	/* Blackness level supported by panel */
	u32 blackness_level;
};

struct mdss_panel_info {
	u32 xres;
	u32 yres;
	u32 physical_width;
	u32 physical_height;
	u32 bpp;
	u32 type;
	u32 wait_cycle;
	u32 pdest;
	u32 brightness_max;
	u32 bl_max;
	u32 bl_min;
	u32 fb_num;
	u64 clk_rate;
	u32 clk_min;
	u64 clk_max;
	u32 mdp_transfer_time_us;
	u32 frame_count;
	u32 is_3d_panel;
	u32 out_format;
	u32 rst_seq[MDSS_DSI_RST_SEQ_LEN];
	u32 rst_seq_len;
	u32 vic; /* video identification code */
	struct mdss_rect roi;
	int pwm_pmic_gpio;
	int pwm_lpg_chan;
	int pwm_period;
	bool dynamic_fps;
	bool ulps_feature_enabled;
	bool ulps_suspend_enabled;
	bool panel_ack_disabled;
	bool esd_check_enabled;
	bool allow_phy_power_off;
	char dfps_update;
	/* new requested fps before it is updated in hw */
	int new_fps;
	/* stores initial fps after boot */
	u32 default_fps;
	/* stores initial vtotal (vfp-method) or htotal (hfp-method) */
	u32 saved_total;
	/* stores initial vfp (vfp-method) or hfp (hfp-method) */
	u32 saved_fporch;
	/* current fps, once is programmed in hw */
	int current_fps;

	int panel_max_fps;
	int panel_max_vtotal;
	u32 mode_gpio_state;
	u32 min_fps;
	u32 max_fps;
	u32 prg_fet;
	struct mdss_panel_roi_alignment roi_alignment;

	u32 cont_splash_enabled;
	bool esd_rdy;
	bool partial_update_supported; /* value from dts if pu is supported */
	bool partial_update_enabled; /* is pu currently allowed */
	u32 dcs_cmd_by_left;
	u32 partial_update_roi_merge;
	struct ion_handle *splash_ihdl;
	int panel_power_state;
	int compression_mode;

	uint32_t panel_dead;
	u32 panel_force_dead;
	u32 panel_orientation;
	bool dynamic_switch_pending;
	bool is_lpm_mode;
	bool is_split_display; /* two DSIs in one display, pp split or not */
	bool use_pingpong_split;

	/*
	 * index[0] = left layer mixer, value of 0 not valid
	 * index[1] = right layer mixer, 0 is possible
	 *
	 * Ex(1): 1080x1920 display using single DSI and single lm, [1080 0]
	 * Ex(2): 1440x2560 display using two DSIs and two lms,
	 *        each with 720x2560, [720 0]
	 * Ex(3): 1440x2560 display using single DSI w/ compression and
	 *        single lm, [1440 0]
	 * Ex(4): 1440x2560 display using single DSI w/ compression and
	 *        two lms, [720 720]
	 * Ex(5): 1080x1920 display using single DSI and two lm, [540 540]
	 * Ex(6): 1080x1920 display using single DSI and two lm,
	 *        [880 400] - not practical but possible
	 */
	u32 lm_widths[2];

	bool is_prim_panel;
	bool is_pluggable;
	char display_id[MDSS_DISPLAY_ID_MAX_LEN];
	bool is_cec_supported;

	/* refer sim_panel_modes enum for different modes */
	u8 sim_panel_mode;

	void *edid_data;
	void *dba_data;
	void *cec_data;

	char panel_name[MDSS_MAX_PANEL_LEN];
	struct mdss_mdp_pp_tear_check te;

	/*
	 * Value of 2 only when single DSI is configured with 2 DSC
	 * encoders. When 2 encoders are used, currently both use
	 * same configuration.
	 */
	u8 dsc_enc_total; /* max 2 */
	struct dsc_desc dsc;

	/*
	 * To determine, if DSC panel requires the pps to be sent
	 * before or after the switch, during dynamic resolution switching
	 */
	bool send_pps_before_switch;

	struct lcd_panel_info lcdc;
	struct fbc_panel_info fbc;
	struct mipi_panel_info mipi;
	struct lvds_panel_info lvds;
	struct edp_panel_info edp;

	bool is_dba_panel;

	/*
	 * Delay(in ms) to accommodate s/w delay while
	 * configuring the event timer wakeup logic.
	 */
	u32 adjust_timer_delay_ms;

	/* debugfs structure for the panel */
	struct mdss_panel_debugfs_info *debugfs_info;

	/* persistence mode on/off */
	bool persist_mode;

	/* HDR properties of display panel*/
	struct mdss_panel_hdr_properties hdr_properties;

	/* DSI to DPI bridge usage */
	bool use_dsi2dpi_bridge;
};

struct mdss_panel_timing {
	struct list_head list;
	const char *name;

	u32 xres;
	u32 yres;

	u32 h_back_porch;
	u32 h_front_porch;
	u32 h_pulse_width;
	u32 hsync_skew;
	u32 v_back_porch;
	u32 v_front_porch;
	u32 v_pulse_width;

	u32 border_top;
	u32 border_bottom;
	u32 border_left;
	u32 border_right;

	u32 lm_widths[2];

	u64 clk_rate;
	char frame_rate;

	u8 dsc_enc_total;
	struct dsc_desc dsc;
	struct fbc_panel_info fbc;
	u32 compression_mode;

	struct mdss_mdp_pp_tear_check te;
	struct mdss_panel_roi_alignment roi_alignment;
};

struct mdss_panel_data {
	struct mdss_panel_info panel_info;
	void (*set_backlight) (struct mdss_panel_data *pdata, u32 bl_level);
	int (*apply_display_setting)(struct mdss_panel_data *pdata, u32 mode);
	unsigned char *mmss_cc_base;

	/**
	 * event_handler() - callback handler for MDP core events
	 * @pdata:	Pointer refering to the panel struct associated to this
	 *		event. Can be used to retrieve panel info.
	 * @e:		Event being generated, see enum mdss_intf_events
	 * @arg:	Optional argument to pass some info from some events.
	 *
	 * Used to register handler to be used to propagate different events
	 * happening in MDP core driver. Panel driver can listen for any of
	 * these events to perform appropriate actions for panel initialization
	 * and teardown.
	 */
	int (*event_handler) (struct mdss_panel_data *pdata, int e, void *arg);
	struct device_node *(*get_fb_node)(struct platform_device *pdev);
	bool (*get_idle)(struct mdss_panel_data *pdata);

	struct list_head timings_list;
	struct mdss_panel_timing *current_timing;
	bool active;

	/* To store dsc cfg name passed by bootloader */
	char dsc_cfg_np_name[MDSS_MAX_PANEL_LEN];
	struct mdss_panel_data *next;

	int panel_te_gpio;
	struct completion te_done;
};

struct mdss_panel_debugfs_info {
	struct dentry *root;
	struct dentry *parent;
	struct mdss_panel_info panel_info;
	u32 override_flag;
	struct mdss_panel_debugfs_info *next;
};

/**
 * mdss_get_panel_framerate() - get panel frame rate based on panel information
 * @panel_info:	Pointer to panel info containing all panel information
 */
static inline u32 mdss_panel_get_framerate(struct mdss_panel_info *panel_info,
					   u32 flags)
{
	u32 frame_rate, pixel_total;
	u64 rate;
	struct mdss_panel_data *panel_data =
			container_of(panel_info, typeof(*panel_data),
					panel_info);
	bool idle = false;

	if (panel_info == NULL) {
		frame_rate = DEFAULT_FRAME_RATE;
		goto end;
	}

	switch (panel_info->type) {
	case MIPI_VIDEO_PANEL:
	case MIPI_CMD_PANEL:
		frame_rate = panel_info->mipi.frame_rate;
		if (panel_data->get_idle)
			idle = panel_data->get_idle(panel_data);
		if (idle)
			frame_rate = panel_info->mipi.frame_rate_idle;
		else
			frame_rate = panel_info->mipi.frame_rate;
		break;
	case EDP_PANEL:
		frame_rate = panel_info->edp.frame_rate;
		break;
	case WRITEBACK_PANEL:
		frame_rate = DEFAULT_FRAME_RATE;
		break;
	case DTV_PANEL:
		if (panel_info->dynamic_fps) {
			frame_rate = panel_info->lcdc.frame_rate;
			break;
		}
	default:
		pixel_total = (panel_info->lcdc.h_back_porch +
			  panel_info->lcdc.h_front_porch +
			  panel_info->lcdc.h_pulse_width +
			  panel_info->xres) *
			 (panel_info->lcdc.v_back_porch +
			  panel_info->lcdc.v_front_porch +
			  panel_info->lcdc.v_pulse_width +
			  panel_info->yres);
		if (pixel_total) {
			rate = panel_info->clk_rate * KHZ_TO_HZ;
			do_div(rate, pixel_total);
			frame_rate = (u32)rate;
		} else {
			frame_rate = DEFAULT_FRAME_RATE;
		}
		break;
	}
end:
	if (flags == FPS_RESOLUTION_KHZ) {
		if (!(frame_rate / KHZ_TO_HZ))
			frame_rate *= KHZ_TO_HZ;
	} else if (flags == FPS_RESOLUTION_HZ) {
		if (frame_rate / KHZ_TO_HZ)
			frame_rate /= KHZ_TO_HZ;
	}

	return frame_rate;
}

/*
 * mdss_panel_get_vtotal() - return panel vertical height
 * @pinfo:	Pointer to panel info containing all panel information
 *
 * Returns the total height of the panel including any blanking regions
 * which are not visible to user but used to calculate panel pixel clock.
 */
static inline int mdss_panel_get_vtotal(struct mdss_panel_info *pinfo)
{
	return pinfo->yres + pinfo->lcdc.v_back_porch +
			pinfo->lcdc.v_front_porch +
			pinfo->lcdc.v_pulse_width+
			pinfo->lcdc.border_top +
			pinfo->lcdc.border_bottom;
}

/*
 * mdss_panel_get_htotal() - return panel horizontal width
 * @pinfo:	Pointer to panel info containing all panel information
 * @compression: true to factor fbc settings, false to ignore.
 *
 * Returns the total width of the panel including any blanking regions
 * which are not visible to user but used for calculations. For certain
 * usescases where the fbc parameters need to be ignored like bandwidth
 * calculation, the appropriate flag can be passed.
 */
static inline int mdss_panel_get_htotal(struct mdss_panel_info *pinfo, bool
		compression)
{
	struct dsc_desc *dsc = NULL;

	int adj_xres = pinfo->xres + pinfo->lcdc.border_left +
				pinfo->lcdc.border_right;

	if (compression) {
		if (pinfo->compression_mode == COMPRESSION_DSC) {
			dsc = &pinfo->dsc;
			adj_xres = dsc->pclk_per_line;
		} else if (pinfo->fbc.enabled) {
			adj_xres = mult_frac(adj_xres,
				pinfo->fbc.target_bpp, pinfo->bpp);
		}
	}

	return adj_xres + pinfo->lcdc.h_back_porch +
		pinfo->lcdc.h_front_porch +
		pinfo->lcdc.h_pulse_width;
}

static inline bool is_dsc_compression(struct mdss_panel_info *pinfo)
{
	if (pinfo)
		return (pinfo->compression_mode == COMPRESSION_DSC);

	return false;
}

int mdss_register_panel(struct platform_device *pdev,
	struct mdss_panel_data *pdata);

/*
 * mdss_panel_is_power_off: - checks if a panel is off
 * @panel_power_state: enum identifying the power state to be checked
 */
static inline bool mdss_panel_is_power_off(int panel_power_state)
{
	return (panel_power_state == MDSS_PANEL_POWER_OFF);
}

/**
 * mdss_panel_is_power_on_interactive: - checks if a panel is on and interactive
 * @panel_power_state: enum identifying the power state to be checked
 *
 * This function returns true only is the panel is fully interactive and
 * opertaing in normal mode.
 */
static inline bool mdss_panel_is_power_on_interactive(int panel_power_state)
{
	return (panel_power_state == MDSS_PANEL_POWER_ON);
}

/**
 * mdss_panel_is_panel_power_on: - checks if a panel is on
 * @panel_power_state: enum identifying the power state to be checked
 *
 * A panel is considered to be on as long as it can accept any commands
 * or data. Sometimes it is posible to program the panel to be in a low
 * power non-interactive state. This function returns false only if panel
 * has explicitly been turned off.
 */
static inline bool mdss_panel_is_power_on(int panel_power_state)
{
	return !mdss_panel_is_power_off(panel_power_state);
}

/**
 * mdss_panel_is_panel_power_on_lp: - checks if a panel is in a low power mode
 * @pdata: pointer to the panel struct associated to the panel
 * @panel_power_state: enum identifying the power state to be checked
 *
 * This function returns true if the panel is in an intermediate low power
 * state where it is still on but not fully interactive. It may or may not
 * accept any commands and display updates.
 */
static inline bool mdss_panel_is_power_on_lp(int panel_power_state)
{
	return !mdss_panel_is_power_off(panel_power_state) &&
		!mdss_panel_is_power_on_interactive(panel_power_state);
}

/**
 * mdss_panel_is_panel_power_on_ulp: - checks if panel is in ultra low power mode
 * @pdata: pointer to the panel struct associated to the panel
 * @panel_power_state: enum identifying the power state to be checked
 *
 * This function returns true if the panel is in a ultra low power
 * state where it is still on but cannot recieve any display updates.
 */
static inline bool mdss_panel_is_power_on_ulp(int panel_power_state)
{
	return panel_power_state == MDSS_PANEL_POWER_LP2;
}

/**
 * mdss_panel_update_clk_rate() - update the clock rate based on panel timing
 *				information.
 * @panel_info:	Pointer to panel info containing all panel information
 * @fps: frame rate of the panel
 */
static inline void mdss_panel_update_clk_rate(struct mdss_panel_info *pinfo,
	u32 fps)
{
	struct lcd_panel_info *lcdc = &pinfo->lcdc;
	u32 htotal, vtotal;

	if (pinfo->type == DTV_PANEL) {
		htotal = pinfo->xres + lcdc->h_front_porch +
				lcdc->h_back_porch + lcdc->h_pulse_width;
		vtotal = pinfo->yres + lcdc->v_front_porch +
				lcdc->v_back_porch + lcdc->v_pulse_width;

		pinfo->clk_rate = mult_frac(htotal * vtotal, fps, 1000);

		pr_debug("vtotal %d, htotal %d, rate %llu\n",
			vtotal, htotal, pinfo->clk_rate);
	}
}

/**
 * mdss_panel_calc_frame_rate() - calculate panel frame rate based on panel timing
 *				information.
 * @panel_info:	Pointer to panel info containing all panel information
 */
static inline u8 mdss_panel_calc_frame_rate(struct mdss_panel_info *pinfo)
{
		u32 pixel_total = 0;
		u8 frame_rate = 0;
		unsigned long pclk_rate = pinfo->mipi.dsi_pclk_rate;
		u32 xres;

		xres = pinfo->xres;
		if (pinfo->compression_mode == COMPRESSION_DSC)
			xres /= 3;

		pixel_total = (pinfo->lcdc.h_back_porch +
			  pinfo->lcdc.h_front_porch +
			  pinfo->lcdc.h_pulse_width +
			  xres) *
			 (pinfo->lcdc.v_back_porch +
			  pinfo->lcdc.v_front_porch +
			  pinfo->lcdc.v_pulse_width +
			  pinfo->yres);

		if (pclk_rate && pixel_total)
			frame_rate =
				DIV_ROUND_CLOSEST(pclk_rate, pixel_total);
		else
			frame_rate = pinfo->panel_max_fps;

		return frame_rate;
}

/**
 * mdss_panel_intf_type: - checks if a given intf type is primary
 * @intf_val: panel interface type of the individual controller
 *
 * Individual controller queries with MDP to check if it is
 * configured as the primary interface.
 *
 * returns a pointer to the configured structure mdss_panel_cfg
 * to the controller that's configured as the primary panel interface.
 * returns NULL on error or if @intf_val is not the configured
 * controller.
 */
struct mdss_panel_cfg *mdss_panel_intf_type(int intf_val);

/**
 * mdss_is_ready() - checks if mdss is probed and ready
 *
 * Checks if mdss resources have been initialized
 *
 * returns true if mdss is ready, else returns false.
 */
bool mdss_is_ready(void);
int mdss_rect_cmp(struct mdss_rect *rect1, struct mdss_rect *rect2);

/**
 * mdss_panel_override_te_params() - overrides TE params to enable SW TE
 * @pinfo: panel info
 */
void mdss_panel_override_te_params(struct mdss_panel_info *pinfo);

/**
 * mdss_panel_dsc_parameters_calc: calculate DSC parameters
 * @dsc: pointer to DSC structure associated with panel_info
 */
void mdss_panel_dsc_parameters_calc(struct dsc_desc *dsc);

/**
 * mdss_panel_dsc_update_pic_dim: update DSC structure with picture dimension
 * @dsc: pointer to DSC structure associated with panel_info
 * @pic_width: Picture width
 * @pic_height: Picture height
 */
void mdss_panel_dsc_update_pic_dim(struct dsc_desc *dsc,
	int pic_width, int pic_height);

/**
 * mdss_panel_dsc_initial_line_calc: update DSC initial line buffering
 * @dsc: pointer to DSC structure associated with panel_info
 * @enc_ip_width: uncompressed input width for DSC enc represented by @dsc
 *              i.e.
 *                 * 720 for full frame single_display_dual_lm: 1440x2560
 *                 * 1080 for full frame dual_display_dual_lm: 2160x3840
 *                 * 360 for partial frame single_display_dual_lm: 360x2560
 */
void mdss_panel_dsc_initial_line_calc(struct dsc_desc *dsc, int enc_ip_width);

/**
 * mdss_panel_dsc_pclk_param_calc: calculate DSC params related to DSI
 * @dsc: pointer to DSC structure associated with panel_info
 * @intf_width: Uncompressed width per interface
 *              i.e.
 *                 * 1440 for full frame single_display_dual_lm: 1440x2560
 *                 * 1080 for full frame dual_display_dual_lm: 2160x3840
 *                 * 720 for partial frame single_display_dual_lm: 720x2560
 */
void mdss_panel_dsc_pclk_param_calc(struct dsc_desc *dsc, int intf_width);

/**
 * mdss_panel_dsc_prepare_pps_buf - prepares Picture Parameter Set to be sent to panel
 * @dsc: pointer to DSC structure associated with panel_info
 * @buf: buffer that holds PPS
 * @pps_id: pps_identifier
 *
 * returns length of the PPS buffer.
 */
int mdss_panel_dsc_prepare_pps_buf(struct dsc_desc *dsc, char *buf,
	int pps_id);
#ifdef CONFIG_FB_MSM_MDSS
int mdss_panel_debugfs_init(struct mdss_panel_info *panel_info,
		char const *panel_name);
void mdss_panel_debugfs_cleanup(struct mdss_panel_info *panel_info);
void mdss_panel_debugfsinfo_to_panelinfo(struct mdss_panel_info *panel_info);

/*
 * mdss_panel_info_from_timing() - populate panel info from panel timing
 * @pt:		pointer to source panel timing
 * @pinfo:	pointer to destination panel info
 *
 * Populates relevant data from panel timing into panel info
 */
void mdss_panel_info_from_timing(struct mdss_panel_timing *pt,
		struct mdss_panel_info *pinfo);

/**
 * mdss_panel_get_timing_by_name() - return panel timing with matching name
 * @pdata:	pointer to panel data struct containing list of panel timings
 * @name:	name of the panel timing to be returned
 *
 * Looks through list of timings provided in panel data and returns pointer
 * to panel timing matching it. If none is found, NULL is returned.
 */
struct mdss_panel_timing *mdss_panel_get_timing_by_name(
		struct mdss_panel_data *pdata,
		const char *name);
#else
static inline int mdss_panel_debugfs_init(
		struct mdss_panel_info *panel_info,
		char const *panel_name) { return 0; };
static inline void mdss_panel_debugfs_cleanup(
		struct mdss_panel_info *panel_info) { };
static inline void mdss_panel_debugfsinfo_to_panelinfo(
		struct mdss_panel_info *panel_info) { };
static inline void mdss_panel_info_from_timing(struct mdss_panel_timing *pt,
		struct mdss_panel_info *pinfo) { };
static inline struct mdss_panel_timing *mdss_panel_get_timing_by_name(
		struct mdss_panel_data *pdata,
		const char *name) { return NULL; };
#endif
#endif /* MDSS_PANEL_H */
